﻿using System;
using System.Data;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Manager;
using SdmxMl.Common;
using SdmxMl.GenericMetadata;
using SdmxMl.Structure;
using Telerik.WinControls;
using Telerik.WinControls.Data;
using Telerik.WinControls.UI;
using Telerik.WinControls.UI.Export;
using SdmxDiff;
using System.Drawing;


namespace ChopPlugin
{
    public partial class UcErhebung : UserControl, PluginInterface.IPlugin
    {
        #region Constants

        public const string ANNOT_ACTIVITY = "CAT_ACTIVITY";
        public const string ANNOT_MJP = "CAT_MJP";
        public const string UNKNOWN = "unknown";

        public const string FICHE_TARGET_ID = "TG_ACTIVITY";
        public const string FICHE_REPORT_ID = "R_FICHE";
        public SmManager sm;

        public const string ERR_CAPTION = "Error";
        public const string EXPORT_CAPTION = "Export";
        const string ERR_OCCURED = "An error occured. Reason: ";
        const string PDF_FILTER = "PDF files (*.pdf)|*.pdf|All files (*.*)|*.*";
        public const string EXCEL_FILTER = "Excel (*.xls)|*.xls";
        public const string MSG_EXPORT_SUCCESS = "The data was exported successfully. Do you want to open the file?";


        // Fiche
        public const string FICHE_COL_NAME = "NAME";
        public const string FICHE_COL_NAME_SHORT = "SHORT";
        public const string FICHE_COL_SINCE = "SINCE";
        public const string FICHE_COL_TYPE = "TYPE";
        public const string FICHE_COL_OBJECT = "OBJECT";
        public const string FICHE_COL_CONTACT_ORG = "CONTACT_ORGANISATION";
        public const string FICHE_COL_ORG_UNIT = "ORGANISATION_UNIT";
        public const string FICHE_COL_CONTACT_NAME = "CONTACT_NAME";
        public const string FICHE_COL_REAL_SURVEY = "REAL_SURVEY";
        public const string FICHE_COL_INST_MAN_LA_OA = "INST_MAN_LA_OA";
        public const string FICHE_COL_TYPE_METH = "TYPE_METH";
        public const string FICHE_COL_COVERAGE_SECTOR = "COVERAGE_SECTOR";
        public const string FICHE_COL_VAREL = "VAREL";
        public const string FICHE_COL_REGIO = "REGIO";
        public const string FICHE_COL_COVERAGE_TIME = "COVERAGE_TIME";
        public const string FICHE_COL_REF_PERIOD = "REF_PERIOD";
        public const string FICHE_COL_FREQ_COL = "FREQ_COL";
        public const string FICHE_COL_DISPO = "DISPO";
        public const string FICHE_COL_REVISION = "REVISION";
        public const string FICHE_COL_QUALITY = "QUALITY";

        #endregion

        private CategorySchemeType catSchemeActivities;
        private CategorySchemeType catSchemeMjp;
        private DataTable tbErhebung;
        private CategorySchemeType catErhebung;

        #region Construction

        public UcErhebung()
        {
            InitializeComponent();
            radMenuExport.Enabled = false;
            radMenuItemPdf.Enabled = false;
            tbErhebung = CreateErhebungTable();

            // Register event for displaying additional info via tooltip
            radGridView.ToolTipTextNeeded += radGridView_ToolTipTextNeeded;

        }
        #endregion

        #region Grid Tooltip event

        /// <summary>Provides Tooltip for coded columns</summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void radGridView_ToolTipTextNeeded(object sender, ToolTipTextNeededEventArgs e)
        {
            GridDataCellElement dataCell = sender as GridDataCellElement;
            if (dataCell != null)
            {
                TextPart textPart = new TextPart(dataCell);
                SizeF size = textPart.Measure(new SizeF(float.PositiveInfinity, float.PositiveInfinity));
                SizeF sizeInCell = textPart.Measure(new SizeF(dataCell.ColumnInfo.Width, float.PositiveInfinity));

                string toolTipText = null;

                float cellWidth = dataCell.ColumnInfo.Width - dataCell.BorderWidth * 2;
                float cellHeight = dataCell.Size.Height - dataCell.BorderWidth * 2;

                if (size.Width > cellWidth || cellHeight < sizeInCell.Height)
                {
                    toolTipText = dataCell.Text;
                }

                e.ToolTipText = toolTipText;
            }
        }
        #endregion

        #region Option Events

        private void radMenuItemFilter_Click(object sender, EventArgs e)
        {
            RadMenuItem menuItem = sender as RadMenuItem;
            if (menuItem != null)
                radGridView.EnableFiltering = menuItem.IsChecked;
        }

        private void radMenuItemExpandGroup_Click(object sender, EventArgs e)
        {
            RadMenuItem menuItem = sender as RadMenuItem;
            if (menuItem != null)
                radGridView.MasterTemplate.AutoExpandGroups = menuItem.IsChecked;
        }



        #endregion

        #region Data Table structure Creation

        private DataTable CreateErhebungTable()
        {
            DataTable tb = new DataTable();
            tb.Columns.Add(new DataColumn("MJP", typeof(string)));
            tb.Columns.Add(new DataColumn("MJP_Name", typeof(string)));
            tb.Columns.Add(new DataColumn("ID", typeof(string)));
            tb.Columns.Add(new DataColumn("Parent_ID", typeof(string)));
            tb.Columns.Add(new DataColumn("Level", typeof(string)));
            tb.Columns.Add(new DataColumn("Text", typeof(string)));

            // Now Fiche
            tb.Columns.Add(new DataColumn(FICHE_COL_NAME, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_NAME_SHORT, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_SINCE, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_TYPE, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_OBJECT, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_CONTACT_ORG, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_ORG_UNIT, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_CONTACT_NAME, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_REAL_SURVEY, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_INST_MAN_LA_OA, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_TYPE_METH, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_COVERAGE_SECTOR, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_VAREL, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_REGIO, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_COVERAGE_TIME, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_REF_PERIOD, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_FREQ_COL, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_DISPO, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_REVISION, typeof(string)));
            tb.Columns.Add(new DataColumn(FICHE_COL_QUALITY, typeof(string)));


            return tb;
        }
        #endregion

        #region IPlugin Members

        /// <summary>Event is part of interface but not used </summary>
        public event PluginInterface.PluginEvent PluginEventExposed
        {
            add { }
            remove { }
        }


        public void Init(System.Xml.XmlDocument xDoc, object obExtend)
        {
        }

        public UserControl VisualComponent()
        {
            return this;
        }

        public bool RequiresInit
        {
            get { return false; }
        }

        #endregion

        #region User control Load event
        private void UcErhebung_Load(object sender, EventArgs e)
        {
            try
            {
                using (new SdmxMl.Helper.CWaitCursor())
                {
              //      ReferenceManager.TreeMgr.AppliClosing += new EventHandler(TreeMgr_AppliClosing);
                    ReferenceManager.TreeMgr.LanguageChange += new EventHandler(TreeMgr_LanguageChange);
                }
            }
            catch (Exception ex)
            {
                RadMessageBox.Show("Error occured during plug-in initialisation! " + ex.Message,
                        ERR_CAPTION, MessageBoxButtons.OK, RadMessageIcon.Error);
            }

        }
        #endregion

        #region Language change Event

        /// <summary>On language change, reload grids with correct texts</summary>
        /// <param name="sender"></param><param name="e"></param>
        void TreeMgr_LanguageChange(object sender, EventArgs e)
        {
            try
            {
                // React only if cache fully loaded
                if (catErhebung != null)
                {
                    radGridView.DataSource = null;
                    FillErhebungTable(catErhebung);
                    radGridView.DataSource = tbErhebung;
                }
            }
            catch (Exception ex)
            {
                RadMessageBox.Show(this, ex.Message, ERR_CAPTION, MessageBoxButtons.OK, RadMessageIcon.Error);
            }
        }
        #endregion

        #region Select Source artefact

        /// <summary>From main tree current selection, request to work with</summary>
        /// <param name="sender"></param><param name="e"></param>
        private void radMenuItemSelectSource_Click(object sender, EventArgs e)
        {
            TreeView tv = ReferenceManager.TreeSdmx;
            if (tv == null)
                return;
            try
            {
                catErhebung = null;
                radGridView.DataSource = null;

                sm = ReferenceManager.GetSmContainerImage();

                DlgVersions aDlg = new DlgVersions();
                aDlg.BindVersionsOf(UrnManager.FullIdToUrn(SdmxArtefactType.CategorySchemes,
                    "CH1+CAT_ERHEBUNG+1.0"));
                if (aDlg.ShowDialog(this) == DialogResult.OK)
                {

                    // If already in memory, navigate otherwhile get from registry
                    UrnParser p = new UrnParser(aDlg.SelectedVersionUrn);
                    if (p.IsSupported)
                    {
                        // If already in memory, navigate otherwhile get from regidtry
                        if (NavigationManager.LocatenavigateProject(p.ArType, p.FullIdent, p) == null)
                            NavigationManager.NavigateWithRegistry(p.ArType, p.FullIdent, true, p);
                    }
                }

                if (tv.SelectedNode != null)
                {
                    using (new SdmxMl.Helper.CWaitCursor())
                    {
                        Artefact a = tv.SelectedNode.Tag as Artefact;
                        if (a != null && a.AgencyId == "CH1" && a.Id == "CAT_ERHEBUNG")
                        {
                            radMenuItemSelectSource.Text = "Source Selected: " + a.FullIdent + " - " + a.Name.ToString();
                            radMenuExport.Enabled = true;
                            radMenuItemPdf.Enabled = true;
                            radMenuItemOptions.Enabled = true;

                            catErhebung = a as CategorySchemeType;
                            FillErhebungTable(catErhebung);
                            radGridView.DataSource = tbErhebung;
                            // Set grid read only
                            radGridView.ReadOnly = true;

                        }
                    }
                }
            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ERR_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        #region Fill Grid

        private void FillErhebungTable(CategorySchemeType catScheme)
        {
            tbErhebung.Rows.Clear();
            foreach (Category cat in catScheme.CategoryList)
            {
                TreatCategory(cat, 1);
            }
        }
        #endregion

        #region Activity

        private void TreatCategory(Category cat, int level)
        {
            // Has link to activity ?
            Category catActivity = GetCategoryFromReferenceInAnnotation(cat.AnnotationList.GetAnnotationType(ANNOT_ACTIVITY), ref catSchemeActivities);
            // Has a linl to MJP
            Category catMjp = catActivity != null ?
                GetCategoryFromReferenceInAnnotation(catActivity.AnnotationList.GetAnnotationType(ANNOT_MJP), ref catSchemeMjp) : null;

            if (catMjp != null)
                catMjp = catMjp.RootItem;

            AttributeValueSetType fiche = AssociatedFiche(cat);

            tbErhebung.Rows.Add(new object[] {
                catMjp == null ? UNKNOWN : catMjp.Id,
                catMjp == null ? string.Empty : catMjp.Name.ToString(),
                cat.Id,
                cat.Parent == null ? string.Empty : cat.Parent,
                level.ToString(),
                cat.Name.ToString(),

                // Fiche
                GetReportedAttribute(FICHE_COL_NAME, fiche),
                GetReportedAttribute(FICHE_COL_NAME_SHORT, fiche),
                GetReportedAttribute(FICHE_COL_SINCE, fiche),
                GetReportedAttribute(FICHE_COL_TYPE, fiche),
                GetReportedAttribute(FICHE_COL_OBJECT, fiche),
                GetReportedAttribute(FICHE_COL_CONTACT_ORG, fiche),
                GetReportedAttribute(FICHE_COL_ORG_UNIT, fiche),
                GetReportedAttribute(FICHE_COL_CONTACT_NAME, fiche),
                GetReportedAttribute(FICHE_COL_REAL_SURVEY, fiche),
                GetReportedAttribute(FICHE_COL_INST_MAN_LA_OA, fiche),
                GetReportedAttribute(FICHE_COL_TYPE_METH, fiche),
                GetReportedAttribute(FICHE_COL_COVERAGE_SECTOR, fiche),
                GetReportedAttribute(FICHE_COL_VAREL, fiche),
                GetReportedAttribute(FICHE_COL_REGIO, fiche),
                GetReportedAttribute(FICHE_COL_COVERAGE_TIME, fiche),
                GetReportedAttribute(FICHE_COL_REF_PERIOD, fiche),
                GetReportedAttribute(FICHE_COL_FREQ_COL, fiche),
                GetReportedAttribute(FICHE_COL_DISPO, fiche),
                GetReportedAttribute(FICHE_COL_REVISION, fiche),
                GetReportedAttribute(FICHE_COL_QUALITY, fiche)

            });

            foreach (Category catChild in cat.CategoryList)
                TreatCategory(catChild, level + 1);
        }

        private string GetReportedAttribute(string conceptId, AttributeValueSetType fiche)
        {
            string val = string.Empty;
            if (fiche != null)
            {
                ReportedAttributeType rp = fiche.ReportedAttributeList.GetReportedAttributeOfConcept(conceptId);
                if (rp != null)
                {
                    val = rp.InternationalizedValue.ToString();
                }
            }
            return val;
        }

        private Category GetCategoryFromReferenceInAnnotation(Annotation a, ref CategorySchemeType catScheme)
        {
            Category catTarget = null;
            // Has link to category ?
            if (a != null && a.Url != null)
            {
                UrnParser pActivity = new UrnParser(a.Url.ToString());
                if (pActivity.IsSupported == false || pActivity.ArType != SdmxArtefactType.CategorySchemes)
                    throw new ApplicationException("Invalid reference: " + a.Url.ToString());

                if (catScheme == null)
                {
                    catScheme = sm.GetArtefact(pActivity.ArType, pActivity.TypedReference, true) as CategorySchemeType;
                    if (catScheme == null)
                        throw new ApplicationException("Unable to load: " + pActivity.FullIdent);
                }
                // Check same  catagory version
                if (catScheme.FullIdent != pActivity.FullIdent)
                    throw new ApplicationException("Invalid. Multiple category schemes refered for Annotation " + a.Type);

                catTarget = catScheme.CategoryList.LocateItemFromFullId(pActivity.SubTypeId, catScheme.CategoryList) as Category;
                if (catTarget == null)
                    throw new ApplicationException("Invalid. Unable to locate referred concept " + pActivity.SubTypeId);
            }
            return catTarget;
        }

        #endregion

        #region associated fiche

        private AttributeValueSetType AssociatedFiche(Category cat)
        {
            // scan referred metaflow of category
            foreach (MetaDataFlowRef mfRef in cat.MetaDataFlowRefList)
            {
                // load flow
                MetadataflowType mf = sm.GetArtefact(SdmxArtefactType.Metadataflows, new ArtefactRefBase(mfRef.FlowId, mfRef.AgencyId, mfRef.Version), true) as MetadataflowType;
                if (mf == null)
                    throw new ApplicationException("Unable to load metaflow: " + mfRef.ToString());

                // Load referred msd only if metadataflow holds an annotation for referring metadataset
                if (!string.IsNullOrEmpty(mf.Uri))
                {
                    MetadataStructureDefinitionType msd = sm.GetArtefact(SdmxArtefactType.MetadataStructureDefinitions,
                       mf.MetadataStructureRef, true) as MetadataStructureDefinitionType;
                    if (msd == null)
                        throw new ApplicationException("Unable to load metadatastructure from reference: " + mf.ToString());

                    // Check expected report
                    if (msd.TargetIdentifiers.FullTargetIdentifier.Id == FICHE_TARGET_ID && msd.ReportStructureList.LocateItem(FICHE_REPORT_ID) != null)
                    {
                        // Correct, get report instance as metadataset
                        MetadataSetType metaset = sm.GetArtefact(SdmxArtefactType.MetadataSet, UrnManager.UrnToArtefactRefTyped(mf.Uri), true) as MetadataSetType;
                        if (metaset == null)
                            throw new ApplicationException("Unable to load metadatastructure from reference: " + metaset.Uri);
                        if (metaset.AttributeValueSetList.Count != 1)
                            throw new ApplicationException("Invalid. Unexpected row count in report for " + metaset.Uri);
                        return metaset.AttributeValueSetList[0];
                    }
                }
            }
            return null;
        }

        #endregion

        #region Excel export

        /// <summary>Excel Export Event</summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void radMenuExport_Click(object sender, EventArgs e)
        {
            RunExportToExcelML();
        }

        /// <summary> Export Grid to Excel </summary>
        private void RunExportToExcelML()
        {
            ExportToExcelML excelExporter = null;
            try
            {
                excelExporter = new ExportToExcelML(this.radGridView);
                //   excelExporter.ExcelCellFormatting += new Telerik.WinControls.UI.Export.ExcelML.ExcelCellFormattingEventHandler(exporter_ExcelCellFormatting);
                excelExporter.SummariesExportOption = SummariesOption.ExportAll;
                //set export settings
                excelExporter.ExportVisualSettings = false;
                excelExporter.ExportHierarchy = true;
                excelExporter.HiddenColumnOption = HiddenOption.DoNotExport;

                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = EXCEL_FILTER;
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    using (new SdmxMl.Helper.CWaitCursor())
                    {
                        excelExporter.RunExport(saveFileDialog.FileName);

                        DialogResult dr = RadMessageBox.Show(MSG_EXPORT_SUCCESS,
                            EXPORT_CAPTION, MessageBoxButtons.YesNo, RadMessageIcon.Question);
                        if (dr == DialogResult.Yes)
                        {
                            System.Diagnostics.Process.Start(saveFileDialog.FileName);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                RadMessageBox.SetThemeName(this.radGridView.ThemeName);
                RadMessageBox.Show(this, ex.Message, ERR_CAPTION, MessageBoxButtons.OK, RadMessageIcon.Error);
            }
        }


        #endregion

    }
}
